From 1e7fb52b21236ef3c3404c15b642de28a723be60 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 26 Sep 2021 16:47:34 +0200 Subject: [PATCH] Add memory formats used by libpng Add unpremultiplied high-depth formats. They are used in the real world, so let's support them. --- gdk/gdkmemoryformat.c | 30 +++++++++++++++++++++++++ gdk/gdkmemorytexture.h | 9 ++++++++ gdk/loaders/gdkpng.c | 32 ++++---------------------- testsuite/gdk/memorytexture.c | 42 +++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 28 deletions(-) diff --git a/gdk/gdkmemoryformat.c b/gdk/gdkmemoryformat.c index 6c746f75df..940e9cea17 100644 --- a/gdk/gdkmemoryformat.c +++ b/gdk/gdkmemoryformat.c @@ -308,6 +308,16 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { r16g16b16a16_to_float, r16g16b16a16_from_float, }, + [GDK_MEMORY_R16G16B16A16] = { + GDK_MEMORY_ALPHA_STRAIGHT, + 8, + G_ALIGNOF (guint16), + TRUE, + TRUE, + { GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT }, + r16g16b16a16_to_float, + r16g16b16a16_from_float, + }, [GDK_MEMORY_R16G16B16_FLOAT] = { GDK_MEMORY_ALPHA_OPAQUE, 6, @@ -328,6 +338,16 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { r16g16b16a16_float_to_float, r16g16b16a16_float_from_float, }, + [GDK_MEMORY_R16G16B16A16_FLOAT] = { + GDK_MEMORY_ALPHA_STRAIGHT, + 8, + G_ALIGNOF (guint16), + TRUE, + TRUE, + { GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, + r16g16b16a16_float_to_float, + r16g16b16a16_float_from_float, + }, [GDK_MEMORY_R32G32B32_FLOAT] = { GDK_MEMORY_ALPHA_OPAQUE, 12, @@ -347,6 +367,16 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { { GL_RGBA32F, GL_RGBA, GL_FLOAT }, r32g32b32a32_float_to_float, r32g32b32a32_float_from_float, + }, + [GDK_MEMORY_R32G32B32A32_FLOAT] = { + GDK_MEMORY_ALPHA_STRAIGHT, + 16, + G_ALIGNOF (float), + TRUE, + TRUE, + { GL_RGBA32F, GL_RGBA, GL_FLOAT }, + r32g32b32a32_float_to_float, + r32g32b32a32_float_from_float, } }; diff --git a/gdk/gdkmemorytexture.h b/gdk/gdkmemorytexture.h index 114922153e..0c574d7add 100644 --- a/gdk/gdkmemorytexture.h +++ b/gdk/gdkmemorytexture.h @@ -46,16 +46,22 @@ G_BEGIN_DECLS * @GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: 4 guint16 values; for red, green, * blue, alpha. The color values are premultiplied with the alpha value. * Since 4.6 + * @GDK_MEMORY_R16G16B16A16: 4 guint16 values; for red, green, blue, alpha. + * Since 4.6 * @GDK_MEMORY_R16G16B16_FLOAT: 3 half-float values; for red, green, blue. * The data is opaque. Since 4.6 * @GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: 4 half-float values; for * red, green, blue and alpha. The color values are premultiplied with * the alpha value. Since 4.6 + * @GDK_MEMORY_R16G16B16A16_FLOAT: 4 half-float values; for red, green, + * blue and alpha. Since 4.6 * @GDK_MEMORY_B32G32R32_FLOAT: 3 float values; for blue, green, red. * The data is opaque. Since 4.6 * @GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: 4 float values; for * red, green, blue and alpha. The color values are premultiplied with * the alpha value. Since 4.6 + * @GDK_MEMORY_R32G32B32A32_FLOAT: 4 float values; for red, green, blue and + * alpha. Since 4.6 * @GDK_MEMORY_N_FORMATS: The number of formats. This value will change as * more formats get added, so do not rely on its concrete integer. * @@ -83,10 +89,13 @@ typedef enum { GDK_MEMORY_B8G8R8, GDK_MEMORY_R16G16B16, GDK_MEMORY_R16G16B16A16_PREMULTIPLIED, + GDK_MEMORY_R16G16B16A16, GDK_MEMORY_R16G16B16_FLOAT, GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R16G16B16A16_FLOAT, GDK_MEMORY_R32G32B32_FLOAT, GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R32G32B32A32_FLOAT, GDK_MEMORY_N_FORMATS } GdkMemoryFormat; diff --git a/gdk/loaders/gdkpng.c b/gdk/loaders/gdkpng.c index 2103ae68f9..526c6fa50f 100644 --- a/gdk/loaders/gdkpng.c +++ b/gdk/loaders/gdkpng.c @@ -206,30 +206,6 @@ unpremultiply_float_to_16bit (guchar *data, } } -static void -premultiply_16bit (guchar *data, - int width, - int height, - int stride) -{ - gsize x, y; - guint16 *src; - - for (y = 0; y < height; y++) - { - src = (guint16 *)data; - for (x = 0; x < width; x++) - { - float alpha = src[x * 4 + 3] / 65535.f; - src[x * 4 ] = (guint16) CLAMP (src[x * 4 ] * alpha, 0.f, 65535.f); - src[x * 4 + 1] = (guint16) CLAMP (src[x * 4 + 1] * alpha, 0.f, 65535.f); - src[x * 4 + 2] = (guint16) CLAMP (src[x * 4 + 2] * alpha, 0.f, 65535.f); - } - - data += stride; - } -} - /* }}} */ /* {{{ Public API */ @@ -333,7 +309,7 @@ gdk_load_png (GBytes *bytes, } else { - format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED; + format = GDK_MEMORY_R16G16B16A16; } break; case PNG_COLOR_TYPE_RGB: @@ -383,9 +359,6 @@ gdk_load_png (GBytes *bytes, png_read_image (png, row_pointers); png_read_end (png, info); - if (format == GDK_MEMORY_R16G16B16A16_PREMULTIPLIED) - premultiply_16bit (buffer, width, height, stride); - out_bytes = g_bytes_new_take (buffer, height * stride); texture = gdk_memory_texture_new (width, height, format, out_bytes, stride); g_bytes_unref (out_bytes); @@ -445,10 +418,13 @@ gdk_save_png (GdkTexture *texture) break; case GDK_MEMORY_R16G16B16: + case GDK_MEMORY_R16G16B16A16: case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: case GDK_MEMORY_R16G16B16_FLOAT: + case GDK_MEMORY_R16G16B16A16_FLOAT: case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: case GDK_MEMORY_R32G32B32_FLOAT: + case GDK_MEMORY_R32G32B32A32_FLOAT: case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: data = g_malloc_n (width * 16, height); gdk_texture_download_float (mtexture, (float *)data, width * 4); diff --git a/testsuite/gdk/memorytexture.c b/testsuite/gdk/memorytexture.c index 60b88465c1..806f7f1d0a 100644 --- a/testsuite/gdk/memorytexture.c +++ b/testsuite/gdk/memorytexture.c @@ -49,14 +49,17 @@ gdk_memory_format_precsion (GdkMemoryFormat format) case GDK_MEMORY_R16G16B16: case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: + case GDK_MEMORY_R16G16B16A16: return 1/65536.f; case GDK_MEMORY_R16G16B16_FLOAT: case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: + case GDK_MEMORY_R16G16B16A16_FLOAT: return 0.0009765625f; case GDK_MEMORY_R32G32B32_FLOAT: case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: + case GDK_MEMORY_R32G32B32A32_FLOAT: return FLT_EPSILON; case GDK_MEMORY_N_FORMATS: @@ -89,13 +92,16 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) return 6; case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: + case GDK_MEMORY_R16G16B16A16: case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: + case GDK_MEMORY_R16G16B16A16_FLOAT: return 8; case GDK_MEMORY_R32G32B32_FLOAT: return 12; case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: + case GDK_MEMORY_R32G32B32A32_FLOAT: return 16; case GDK_MEMORY_N_FORMATS: @@ -125,8 +131,11 @@ gdk_memory_format_has_alpha (GdkMemoryFormat format) case GDK_MEMORY_R8G8B8A8: case GDK_MEMORY_A8B8G8R8: case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: + case GDK_MEMORY_R16G16B16A16: case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: + case GDK_MEMORY_R16G16B16A16_FLOAT: case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: + case GDK_MEMORY_R32G32B32A32_FLOAT: return TRUE; case GDK_MEMORY_N_FORMATS: @@ -296,6 +305,17 @@ texture_builder_set_pixel (TextureBuilder *builder, memcpy (data, pixels, 4 * sizeof (guint16)); } break; + case GDK_MEMORY_R16G16B16A16: + { + guint16 pixels[4] = { + CLAMP (color->red * 65536.f, 0, 65535.f), + CLAMP (color->green * 65536.f, 0, 65535.f), + CLAMP (color->blue * 65536.f, 0, 65535.f), + CLAMP (color->alpha * 65536.f, 0, 65535.f), + }; + memcpy (data, pixels, 4 * sizeof (guint16)); + } + break; case GDK_MEMORY_R16G16B16_FLOAT: { guint16 pixels[3] = { @@ -317,6 +337,17 @@ texture_builder_set_pixel (TextureBuilder *builder, memcpy (data, pixels, 4 * sizeof (guint16)); } break; + case GDK_MEMORY_R16G16B16A16_FLOAT: + { + guint16 pixels[4] = { + float_to_half (color->red), + float_to_half (color->green), + float_to_half (color->blue), + float_to_half (color->alpha) + }; + memcpy (data, pixels, 4 * sizeof (guint16)); + } + break; case GDK_MEMORY_R32G32B32_FLOAT: { float pixels[3] = { @@ -338,6 +369,17 @@ texture_builder_set_pixel (TextureBuilder *builder, memcpy (data, pixels, 4 * sizeof (float)); } break; + case GDK_MEMORY_R32G32B32A32_FLOAT: + { + float pixels[4] = { + color->red, + color->green, + color->blue, + color->alpha + }; + memcpy (data, pixels, 4 * sizeof (float)); + } + break; case GDK_MEMORY_N_FORMATS: default: g_assert_not_reached (); -- 2.30.2